fix!(codegen): reset function outputs and default omitted arguments - #1958
Conversation
|
3 findings in 4m 31s for $0.73 between
|
Build Artifacts🐧 Linux
From workflow run 🪟 Windows
From workflow run |
|
2 findings in 5m 10s for $0.72 between
|
|
3 findings in 3m 35s for $0.75 between
|
|
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5e0e6decf1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| let temp = builder.build_alloca(temp_type, "empty_varinout")?; | ||
| builder.build_store(temp, temp_type.const_zero())?; |
There was a problem hiding this comment.
Apply type defaults to empty stateful in-out arguments
When a program or function-block call passes an empty VAR_IN_OUT whose target type has a nonzero default, for example TYPE T : DINT := 20 and fb(x := ), this branch always writes LLVM zero into the temporary. The function-call path uses get_initial_value, and the updated codegen documentation promises default-or-zero behavior, so the callee sees 0 instead of 20. Initialize the temporary from the parameter or type default before falling back to zero.
AGENTS.md reference: AGENTS.md:L42-L42
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
The path at src/codegen/generators/expression_generator.rs#L1698-L1711 now hands the parameter entry to the same generate_empty_expression the function-call path uses, so the temporary starts at the parameter's default, then the type's default, then zero. The literal zero store remains only as a fallback when no parameter entry exists.
One finding for the reviewer: validation rejects this call shape from real source. inst(x := ) on a function block fails with E031, which demands a reference for an in-out. So the scenario is reachable only from codegen unit tests, which bypass validation. I could not write a lit test for it. Instead I added a unit test next to the existing one, program_empty_inout_assignment_takes_type_default, with an inline snapshot that shows store i32 20 into the temporary. The existing sibling snapshot changed only in the alloca's name.
| &function_context, | ||
| debug, | ||
| )?; | ||
| self.generate_initialization_of_output_params(&pou_members, &local_index)?; |
There was a problem hiding this comment.
Update the POU internals page for output resets
This new initialization call makes every function or method output start at its default value, but book/technical/internals/00-pous.md still says that only locals and the return variable are initialized and shows scale IR with no store through %overflow. Update that paragraph and IR example so the technical book describes the behavior introduced here.
AGENTS.md reference: AGENTS.md:L42-L42
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
book/technical/internals/00-pous.md#L276 now says a function also starts each output at its initial value or zero through the caller's address. The scale IR example gained the load of the output pointer and the zero store after the return variable is zeroed, matching the real emission order. The closing sentence notes that flag holds the default even on a path that never assigns it.
|
5 findings in 4m 26s for $0.76 between
|
|
4 findings in 3m 32s for $0.70 between
|
|
4 findings in 4m 48s for $0.58 between
|
|
2 findings in 3m 57s for $0.54 between
|
|
4 findings in 3m 51s for $0.67 between
|
|
1 finding in 4m 38s for $0.70 between
|
|
1 finding in 3m 37s for $0.73 between
|
@ghaith or @volsa this one needs a careful review, it made some assumptions in codegen that seem right... but a few of the polymorphism tests have been changed. So a double check of this is probably necessary.
Problem: When a call left out an argument, the compiler passed the contents of a stack slot that nothing had written. The callee then saw whatever the previous call had left there. A VAR_OUTPUT of a function or method also started every call with the caller's current value, so a path that did not assign the output leaked that value back to the caller.
Solution: An argument that is left out, or written empty, now carries the declared default or zero. Every VAR_OUTPUT of a function or method is initialized like a local variable at the start of the call: codegen zero-fills it through the caller's address, and the init lowering adds the constructor call and the initializer assignment. Variable length array outputs keep the caller's bounds and are not reset. Reading an output before assigning it now gives its default, so callers no longer observe stale values. One known effect is that passing the same variable as an output and as an in-out of one call makes the body read zero; the book documents this.
Refs: PRG-4940
🤖 Generated with Claude Code